//\file: Vector3.cc

#include"Vector3.h"
#include <trax.hpp>

namespace AtomTrace{

	/**
	const Vector3 Vector3::ZERO(0.0f, 0.0f, 0.0f);
	const Vector3 Vector3::UNIT_X(1.0f, 0.0f, 0.0f);
	const Vector3 Vector3::UNIT_Y(0.0f, 1.0f, 0.0f);
	const Vector3 Vector3::UNIT_Z(0.0f, 0.0f, 1.0f);
	**/

	Vector3::Vector3():
		_x(0.0f),
		_y(0.0f),
		_z(0.0f)
	{}

	Vector3::Vector3(float ix, float iy, float iz):
		_x(ix),
		_y(iy),
		_z(iz)
	{}

	Vector3::Vector3(const float val):
		_x(val),
		_y(val),
		_z(val)
	{}

	Vector3::Vector3(const Vector3 & other):
		_x(other._x),
		_y(other._y),
		_z(other._z)
	{}

	Vector3::Vector3(int address)
	{
		_x = loadf(address, 0);
		_y = loadf(address, 1);
		_z = loadf(address, 2);
	}

	void Vector3::Set(float ix, float iy, float iz)
	{
		_x = ix;
		_y = iy;
		_z = iz;
	}

	const float & Vector3::operator[](int index) const
	{
		return *((&_x)+index);
	}

	float & Vector3::operator[](int index)
	{
		return *((&_x)+index);
	}

	const Vector3 & Vector3::operator=(const Vector3 & rhs)
	{
		_x = rhs._x;
		_y = rhs._y;
		_z = rhs._z;

		return *this;
	}

	const Vector3 & Vector3::operator=(const float val)
	{
		_x = _y = _z = val;
		return *this;
	}

	const Vector3 Vector3::operator+(const Vector3 & rhs) const
	{
		return Vector3(_x+rhs._x, _y+rhs._y, _z+rhs._z);
	}

	const Vector3 Vector3::operator-(const Vector3 & rhs) const
	{
		return Vector3(_x-rhs._x, _y-rhs._y, _z-rhs._z);
	}

	const Vector3 Vector3::operator*(float rhs) const //scale
	{
		// should detect if rhs is nan in C++
		return Vector3(_x*rhs, _y*rhs, _z*rhs);
	}

	const Vector3 Vector3::operator/(float rhs) const //scale
	{
		//assert(!isNAN(rhs));
		//assert(rhs >= 0.000001f || rhs <= -0.000001f);
		return Vector3(_x/rhs, _y/rhs, _z/rhs);
	}

	const Vector3 & Vector3::operator+=(const Vector3 &rhs)
	{
		_x += rhs._x;
		_y += rhs._y;
		_z += rhs._z;
		return *this;
	}

	const Vector3 & Vector3::operator-=(const Vector3 &rhs)
	{
		_x -= rhs._x;
		_y -= rhs._y;
		_z -= rhs._z;
		return *this;
	}

		const Vector3 & Vector3::operator*=(const float val)
		{
			_x *= val;
			_y *= val;
			_z *= val;
			return *this;
		}

	const float Vector3::Dot(const Vector3 & rhs) const
	{
		return (_x*rhs._x + _y*rhs._y + _z*rhs._z);
	}

	const Vector3 Vector3::Cross(const Vector3 & rhs) const
	{
		Vector3 resVec( _y * rhs._z - _z * rhs._y,
						_z * rhs._x - _x * rhs._z,
						_x * rhs._y - _y * rhs._x);
		return resVec;
	}


	const Vector3 Vector3::GetNormalize(void) const
	{
		float fac = invsqrt(_x*_x + _y*_y + _z*_z);
		return Vector3(_x*fac, _y*fac, _z*fac);
	}

	void Vector3::Normalize(void)
	{
		float fac = invsqrt(_x*_x + _y*_y + _z*_z);
		//assert(fac > 0.0001f);
		_x *= fac;
		_y *= fac;
		_z *= fac;
	}

	const float Vector3::Length() const
	{
		return sqrt(_x*_x + _y*_y + _z*_z);
	}

	const float Vector3::LengthSquare() const
	{
		return (_x*_x + _y*_y + _z*_z);
	}

	void Vector3::DebugPrint() const
	{
		printf("[%.2f, %.2f, %.2f]", _x, _y, _z);
	}

} // namespace AtomTrace


